//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package docker_dao

import (
	"context"
	"fmt"

	"atomgit.com/openlinksaas/api-server/dao/db_ns"
	"atomgit.com/openlinksaas/proto-gen-go.git/docker_template_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type AppImageDbItem struct {
	AppImageId  string `bson:"_id"  json:"_id"`
	AppId       string `bson:"appId"  json:"appId"`
	ThumbFileId string `bson:"thumbFileId"  json:"thumbFileId"`
	RawFileId   string `bson:"rawFileId"  json:"rawFileId"`
	Weight      uint32 `bson:"weight"  json:"weight"`
}

func (item *AppImageDbItem) ToAppImage() *docker_template_api.AppImage {
	return &docker_template_api.AppImage{
		ThumbFileId: item.ThumbFileId,
		RawFileId:   item.RawFileId,
		Weight:      item.Weight,
	}
}

type _AppImageDao struct {
	mc *mongo.Collection
}

func newAppImageDao(db *mongo.Database) (*_AppImageDao, error) {
	mc := db.Collection(db_ns.DB_NS_DOCKER + "image")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"appId", 1}, {"weight", -1}},
	})
	if err != nil {
		return nil, err
	}
	return &_AppImageDao{mc: mc}, nil
}

func (db *_AppImageDao) Insert(ctx context.Context, dbItem *AppImageDbItem) error {
	dbItem.AppImageId = db.genAppImageId(dbItem.AppId, dbItem.ThumbFileId, dbItem.RawFileId)
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_AppImageDao) genAppImageId(appId, thumbFileId, rawFileId string) string {
	return fmt.Sprintf("%s:%s:%s", appId, thumbFileId, rawFileId)
}

func (db *_AppImageDao) Exist(ctx context.Context, appId, thumbFileId, rawFileId string) (bool, error) {
	appImageId := db.genAppImageId(appId, thumbFileId, rawFileId)
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": appImageId, "appId": appId})
	return count > 0, err
}

func (db *_AppImageDao) Remove(ctx context.Context, appId, thumbFileId, rawFileId string) error {
	appImageId := db.genAppImageId(appId, thumbFileId, rawFileId)
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": appImageId, "appId": appId})
	return err
}

func (db *_AppImageDao) RemoveByApp(ctx context.Context, appId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"appId": appId})
	return err
}

func (db *_AppImageDao) ListByApp(ctx context.Context, appIdList []string) ([]*AppImageDbItem, error) {
	if len(appIdList) == 0 {
		return []*AppImageDbItem{}, nil
	}
	cursor, err := db.mc.Find(ctx, bson.M{"appId": bson.M{"$in": appIdList}}, options.Find().SetSort(bson.M{"weight": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*AppImageDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_AppImageDao) ListAll(ctx context.Context) ([]*AppImageDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{}, options.Find().SetSort(bson.D{{"weight", -1}, {"_id", 1}}))
	if err != nil {
		return nil, err
	}
	retList := []*AppImageDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_AppImageDao) UpdateWeight(ctx context.Context, appId, thumbFileId, rawFileId string, weight uint32) error {
	appImageId := db.genAppImageId(appId, thumbFileId, rawFileId)
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": appImageId, "appId": appId}, bson.M{"$set": bson.M{"weight": weight}})
	return err
}
